use crate::ast::*;
use crate::error::{CompilerError, Result};
use super::super::TypeEnvironment;
use super::super::TypeInference;

impl TypeInference {



    /// Infer types in a field access expression
    pub(in crate::type_check::type_inference) fn infer_field_access_expression(
        &mut self,
        field_access: &FieldAccessExpr,
        env: &mut TypeEnvironment,
    ) -> Result<Type> {
        // Infer object type
        let _object_type = self.infer_expression(&field_access.object, env)?;

        // TODO: Look up field type in object type
        // For now, return any
        Ok(Type::Basic(crate::ast::types::BasicType::Any))
    }



    /// Infer types in an index access expression
    pub(in crate::type_check::type_inference) fn infer_index_access_expression(
        &mut self,
        index_access: &IndexAccessExpr,
        env: &mut TypeEnvironment,
    ) -> Result<Type> {
        // Infer object type
        let object_type = self.infer_expression(&index_access.object, env)?;

        match object_type {
            Type::Array(array_type) => Ok(*array_type.element_type.clone()),
            Type::Vec(vector_type) => Ok(*vector_type.element_type.clone()),
            Type::Map(map_type) => Ok(*map_type.value_type.clone()),
            _ => Err(CompilerError::type_error(
                index_access.location.line,
                index_access.location.column,
                "Cannot index non-indexable type",
            )),
        }
    }



    /// Infer types in a slice range expression
    pub(in crate::type_check::type_inference) fn infer_slice_range_expression(
        &mut self,
        slice_range: &SliceRangeExpr,
        env: &mut TypeEnvironment,
    ) -> Result<Type> {
        // Infer object type
        let object_type = self.infer_expression(&slice_range.object, env)?;

        // Slice range only works on slices (not arrays)
        match object_type {
            Type::Vec(vector_type) => {
                // Infer start index type if present
                if let Some(start) = &slice_range.start {
                    let start_type = self.infer_expression(start, env)?;
                    // Verify start is an integer type
                    match start_type {
                        Type::Basic(crate::ast::types::BasicType::Int)
                        | Type::Basic(crate::ast::types::BasicType::Int32)
                        | Type::Basic(crate::ast::types::BasicType::Int64) => {}
                        _ => {
                            return Err(CompilerError::type_error(
                                slice_range.location.line,
                                slice_range.location.column,
                                "Slice range start index must be an integer type",
                            ));
                        }
                    }
                }

                // Infer end index type if present
                if let Some(end) = &slice_range.end {
                    let end_type = self.infer_expression(end, env)?;
                    // Verify end is an integer type
                    match end_type {
                        Type::Basic(crate::ast::types::BasicType::Int)
                        | Type::Basic(crate::ast::types::BasicType::Int32)
                        | Type::Basic(crate::ast::types::BasicType::Int64) => {}
                        _ => {
                            return Err(CompilerError::type_error(
                                slice_range.location.line,
                                slice_range.location.column,
                                "Slice range end index must be an integer type",
                            ));
                        }
                    }
                }

                // Slice range returns a slice of the same element type
                Ok(Type::Vec(vector_type))
            }
            _ => Err(CompilerError::type_error(
                slice_range.location.line,
                slice_range.location.column,
                "Slice range operation only supported on slice types",
            )),
        }
    }



    /// Infer types in a cast expression
    pub(in crate::type_check::type_inference) fn infer_cast_expression(
        &mut self,
        cast: &CastExpr,
        env: &mut TypeEnvironment,
    ) -> Result<Type> {
        // Infer expression type
        let _expr_type = self.infer_expression(&cast.expr, env)?;

        // Return target type
        Ok(cast.target_type.clone())
    }

}
